package com.tbit.main.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.tbit.common.utils.GPSUtil;
import com.tbit.main.constant.*;
import com.tbit.main.constant.enums.MachineAlarmEnum;
import com.tbit.main.pojo.*;
import com.tbit.common.entity.GPS.CarHistory;
import com.tbit.main.remote.map.TXHttpClient;
import com.tbit.main.remote.sms.XCSmsClient;
import com.tbit.main.service.*;
import com.tbit.main.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

import static com.tbit.main.constant.AccountSmsModelConstant.SMS_DS;
import static com.tbit.main.constant.AccountSmsModelConstant.SMS_ZC;

/**
 * @author LMY
 * @create 2020-11-17 9:32
 */
@Slf4j
@Service("oracleJobService")
public class OracleJobServiceImpl implements OracleJobService {
    @Autowired
    private MachineAlarmService machineAlarmService;
    @Autowired
    private MachineAlarmLogService machineAlarmLogService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private MachineStatusService machineStatusService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private MachineService machineService;
    @Autowired
    private MachineAttrService machineAttrService;
    @Autowired
    private MachineBorrowService machineBorrowService;
    @Autowired
    private RideLogService rideLogService;
    @Autowired
    private ParkService parkService;
    @Autowired
    private UserService userService;
    @Autowired
    private SmsAuthConfigService smsAuthConfigService;
    @Autowired
    private MachineLastUseLogService machineLastUseLogService;
    @Autowired
    private MainCarService mainCarService;
    @Autowired
    private DataService dataService;
    @Autowired
    private MachineLoseService machineLoseService;
    @Autowired
    private GeoreMachineService georeMachineService;
    @Autowired
    private BrandRemoteConfigService brandRemoteConfigService;
    @Autowired
    private MachineLastUseService machineLastUseService;
    @Autowired
    private MachineAbnormalService machineAbnormalService;

    @Override
    //@Scheduled(cron = "0 13/33 * * * ?")
    /**资产预警无信号定时任务*/
    public void noSignalMachine() {
        LogUtil.info("资产预警无信号定时任务！");
        long t1 = System.currentTimeMillis();

        /* 获取所有无信号资产预警配置，添加到数据集合*/
        Map<Integer, OracleJob> mapOracleJob = markSms(MachineAlarmEnum.MACHINE_ALARM_OFFLINE.getAlarmCode());

        /**获取所有短信模板配置*/
        List<Integer> listAccountId = markAccountId(mapOracleJob, SMS_ZC);

        /* 筛选车辆*/
        if (listAccountId != null && listAccountId.size() > 0) {
            for (Integer key : mapOracleJob.keySet()) {
                String location = DateTimeUtil.getMinsAgo(mapOracleJob.get(key).getOfflineAlarmTime());
                List<Machine> machineStatuses = machineStatusService.getByBatDt(key, location, null);
                if (machineStatuses.size() > 0) {
                    List<String> userCode = new ArrayList<>();
                    Map<Integer, String> userCodeId = new HashMap<>();
                    for (Machine machine : machineStatuses) {
                        String redisUserCode = redisService.get(RedisConstant.REDIS_KEY_MACHINE + MachineAlarmEnum.MACHINE_ALARM_OFFLINE.getAlarmType() + machine.getAccountId() + machine.getUserCode());
                        if (redisUserCode == null) {
                            /* 存放redis一天*/
                            redisService.add(RedisConstant.REDIS_KEY_MACHINE + MachineAlarmEnum.MACHINE_ALARM_OFFLINE.getAlarmType() + machine.getAccountId() + machine.getUserCode(), machine.getUserCode(), 24 * 3600);
                            userCode.add(machine.getUserCode());
                            userCodeId.put(machine.getMachineId(), machine.getUserCode());
                        }
                    }
                    if (userCode.size() > 0) {
                        //获取分区id
                        List<Map<String, Object>> mapList = getRegionId(userCodeId);

                        OracleJob oracleJob = mapOracleJob.get(key);

                        //发送短信
                        if (oracleJob.getAccountSms() != null) {
                            sendSmsCL(MachineAlarmEnum.MACHINE_ALARM_OFFLINE.getAlarmDesc(), userCode, oracleJob);
                        } else {
                            sendSms(MachineAlarmEnum.MACHINE_ALARM_OFFLINE.getAlarmDesc(), userCode, oracleJob);
                        }

                        //插入日志
                        machineAlarmLogService.insertBatchMap(key, MachineAlarmEnum.MACHINE_ALARM_OFFLINE.getAlarmType(), mapList, DateTimeUtil.getNowTime());
                    }
                }
            }
        }
        long t2 = System.currentTimeMillis();
        LogUtil.info("无信号定时任务时间" + (t2 - t1) + "ms");
    }

    @Override
    // @Scheduled(cron = "0 7/15 * * * ?")
    /**资产预警断电定时任务*/
    public void outAgeMachine() {
        LogUtil.info("资产预警断电定时任务！");
        long t1 = System.currentTimeMillis();

        /* 获取所有断电资产预警配置，添加到运营区域数据集合*/
        Map<Integer, OracleJob> mapOracleJob = markSms("powerAlarmSwitch");

        /**获取所有短信模板配置*/
        List<Integer> listAccountId = markAccountId(mapOracleJob, SMS_ZC);

        if (listAccountId != null && listAccountId.size() > 0) {
            for (Integer key : mapOracleJob.keySet()) {
                List<Machine> machineStatuses = machineStatusService.getByBatDt(key, null, 10000);

                if (machineStatuses.size() > 0) {
                    List<String> userCode = new ArrayList<>();
                    Map<Integer, String> userCodeId = new HashMap<>();
                    for (Machine machine : machineStatuses) {
                        /**判断是否正常换电*/
                        String powerChangeLogString = redisService.get(RedisConstant.REDIS_TER_BATTERY_CHANGE + machine.getMachineNO());
                        if (powerChangeLogString == null) {
                            String redisUserCode = redisService.get(RedisConstant.REDIS_KEY_MACHINE + MachineAlarmEnum.MACHINE_ALARM_POWER.getAlarmType() + machine.getAccountId() + machine.getUserCode());
                            if (redisUserCode == null) {
                                /* 存放redis一天*/
                                redisService.add(RedisConstant.REDIS_KEY_MACHINE + MachineAlarmEnum.MACHINE_ALARM_POWER.getAlarmType() + machine.getAccountId() + machine.getUserCode(), machine.getUserCode(), 24 * 3600);
                                userCode.add(machine.getUserCode());
                                userCodeId.put(machine.getMachineId(), machine.getUserCode());
                            }
                        }
                    }
                    if (userCode.size() > 0) {
                        //获取分区id
                        List<Map<String, Object>> mapList = getRegionId(userCodeId);

                        OracleJob oracleJob = mapOracleJob.get(key);
                        //发送短信
                        if (oracleJob.getAccountSms() != null) {
                            sendSmsCL(MachineAlarmEnum.MACHINE_ALARM_POWER.getAlarmDesc(), userCode, oracleJob);
                        } else {
                            sendSms(MachineAlarmEnum.MACHINE_ALARM_POWER.getAlarmCode(), userCode, oracleJob);
                        }
                        //插入日志
                        machineAlarmLogService.insertBatchMap(key, MachineAlarmEnum.MACHINE_ALARM_POWER.getAlarmType(), mapList, DateTimeUtil.getNowTime());
                    }
                }
            }
        }
        long t2 = System.currentTimeMillis();
        LogUtil.info("断电预警定时任务时间" + (t2 - t1) + "ms");
    }

    @Override
    //@Scheduled(cron = "0 2/3 * * * ?")
    /**资产预警超区定时任务*/
    public void superzoneMachine() {
        LogUtil.info("资产预警超区定时任务！");
        long t1 = System.currentTimeMillis();

        /**资产配置信息，运营区域信息，添加到数据集合*/
        Map<Integer, OracleJob> mapOracleJob = markSms(MachineAlarmEnum.MACHINE_ALARM_GEO.getAlarmCode());

        /**获取所有短信模板配置*/
        List<Integer> listAccountId = markAccountId(mapOracleJob, SMS_ZC);

        if (listAccountId != null && listAccountId.size() > 0) {
            /**查询定位五分钟内车辆*/
            List<Integer> listMachine = machineStatusService.getByPosDt(DateTimeUtil.getMinsAgo(5));
            if (listMachine != null && listMachine.size() > 0) {
                /**查询设备最后状态*/
                List<MachineStatus> listMachineStatus = machineStatusService.getByMachineIdBatch(listMachine);
                Map<Integer, List<MachineStatus>> machineStatusMap = new HashMap<>();
                for (MachineStatus machineStatus : listMachineStatus) {
                    if (machineStatusMap.get(machineStatus.getAccountId()) == null) {
                        List<MachineStatus> machineStatuses = new ArrayList<>();
                        machineStatuses.add(machineStatus);
                        machineStatusMap.put(machineStatus.getAccountId(), machineStatuses);
                    } else {
                        machineStatusMap.get(machineStatus.getAccountId()).add(machineStatus);
                    }
                }

                Map<Integer, CopyOnWriteArrayList<String>> listMap = new HashMap<>();
                for (Integer key : mapOracleJob.keySet()) {
                    if (machineStatusMap.get(key) != null) {
                        for (MachineStatus machineStatus : machineStatusMap.get(key)) {
                            Point point = new Point();
                            point.setX(machineStatus.getLon());
                            point.setY(machineStatus.getLat());
                            /**排除在区域内的*/
                            if (!GeoUtil.IsPtInPoly(point, mapOracleJob.get(key).getPoints())) {
                                if (listMap.get(key) == null) {
                                    CopyOnWriteArrayList<String> machineNo = new CopyOnWriteArrayList<>();
                                    machineNo.add(machineStatus.getMachineNO());
                                    listMap.put(key, machineNo);
                                } else {
                                    listMap.get(key).add(machineStatus.getMachineNO());
                                }
                            }
                        }
                    }
                }
                if (listMap != null && listMap.size() > 0) {
                    /**循环区域配置信息*/
                    for (Integer key : listMap.keySet()) {
                        /**判断运营区域的短信模板*/
                        if (mapOracleJob.get(key).getAccountSms() != null || mapOracleJob.get(key).getSmsCodeKey() != null) {

                            Iterator<String> iterator = listMap.get(key).iterator();
                            while (iterator.hasNext()) {
                                String machineNo = iterator.next();
                                String redisMachineNO = redisService.get(MachineAlarmEnum.MACHINE_ALARM_GEO.getAlarmType() + RedisConstant.REDIS_KEY_MACHINE + machineNo);
                                if (redisMachineNO == null) {
                                    /**存放redis*/
                                    redisService.add(MachineAlarmEnum.MACHINE_ALARM_GEO.getAlarmType() + RedisConstant.REDIS_KEY_MACHINE + machineNo, machineNo, 24 * 3600);
                                } else {
                                    listMap.get(key).remove(machineNo);
                                }
                            }
                        }
                        if (listMap.get(key).size() > 0) {
                            List<Machine> machines = machineService.getByMachineNOs(listMap.get(key));
                            List<String> userCode = machines.stream().map(Machine::getUserCode).collect(Collectors.toList());
                            Map<Integer, String> userCodeId = new HashMap<>();
                            for (Machine machine : machines) {
                                userCodeId.put(machine.getMachineId(), machine.getUserCode());
                            }

                            //获取分区id
                            List<Map<String, Object>> mapList = getRegionId(userCodeId);

                            OracleJob oracleJob = mapOracleJob.get(key);
                            /**发送短信*/
                            if (oracleJob.getAccountSms() != null) {
                                sendSmsCL(MachineAlarmEnum.MACHINE_ALARM_GEO.getAlarmDesc(), userCode, oracleJob);
                            } else {
                                sendSms(MachineAlarmEnum.MACHINE_ALARM_GEO.getAlarmDesc(), userCode, oracleJob);
                            }

                            /**添加预警日志*/
                            machineAlarmLogService.insertBatchMap(key, MachineAlarmEnum.MACHINE_ALARM_GEO.getAlarmType(), mapList, DateTimeUtil.getNowTime());
                        }
                    }
                }
            }
        }
        long t2 = System.currentTimeMillis();
        LogUtil.info("超区预警定时任务时间" + (t2 - t1) + "ms");
    }

    @Override
    //@Scheduled(cron = "0 0 17 * * ?")
    /**资产预警闲置定时任务*/
    public void leaveMachine() {
        LogUtil.info("资产预警闲置定时任务！");
        long t1 = System.currentTimeMillis();

        /* 获取所有闲置资产预警配置，添加到数据集合*/
        Map<Integer, OracleJob> mapOracleJob = markSms(MachineAlarmEnum.MACHINE_ALARM_IDLE.getAlarmCode());

        /**获取所有短信模板配置*/
        List<Integer> listAccountId = markAccountId(mapOracleJob, SMS_ZC);

        if (listAccountId != null && listAccountId.size() > 0) {
            for (Integer key : mapOracleJob.keySet()) {
                /**获取超区车辆*/
                String location = DateTimeUtil.getHoursAgo(mapOracleJob.get(key).getIdleAlarmTime());
                List<MachineStatusBorrow> listMachineStatus = machineStatusService.getUnUseByAccountId(key, location);

                if (CollUtil.isNotEmpty(listMachineStatus)) {
                    List<String> userCode = new ArrayList<>();
                    Map<Integer, String> userCodeId = new HashMap<>();
                    for (MachineStatusBorrow machine : listMachineStatus) {
                        String redisUserCode = redisService.get(RedisConstant.REDIS_KEY_MACHINE + MachineAlarmEnum.MACHINE_ALARM_IDLE.getAlarmType() + machine.getAccountId() + machine.getUserCode());
                        if (redisUserCode == null) {
                            /* 存放redis一天*/
                            redisService.add(RedisConstant.REDIS_KEY_MACHINE + MachineAlarmEnum.MACHINE_ALARM_IDLE.getAlarmType() + machine.getAccountId() + machine.getUserCode(), machine.getUserCode(), 2 * 24 * 3600);
                            userCode.add(machine.getUserCode());
                            userCodeId.put(machine.getMachineId(), machine.getUserCode());
                        }
                    }
                    if (userCode.size() > 0) {
                        //获取分区id
                        List<Map<String, Object>> mapList = getRegionId(userCodeId);

                        OracleJob oracleJob = mapOracleJob.get(key);
                        //发送短信
                        if (oracleJob.getAccountSms() != null) {
                            sendSmsCL(MachineAlarmEnum.MACHINE_ALARM_IDLE.getAlarmDesc(), userCode, oracleJob);
                        } else {
                            sendSms(MachineAlarmEnum.MACHINE_ALARM_IDLE.getAlarmDesc(), userCode, oracleJob);
                        }
                        //插入日志
                        machineAlarmLogService.insertBatchMap(key, MachineAlarmEnum.MACHINE_ALARM_IDLE.getAlarmType(), mapList, DateTimeUtil.getNowTime());
                    }
                }
            }
        }
        long t2 = System.currentTimeMillis();
        LogUtil.info("闲置预警定时任务时间" + (t2 - t1) + "ms");
    }

    @Override
    //@Scheduled(cron = "0 0 5/6 * * ?")
    /**资产预警无定位定时任务*/
    public void locationMachine() {
        LogUtil.info("资产预警无定位定时任务！");
        long t1 = System.currentTimeMillis();

        /**获取短信*/
        Map<Integer, OracleJob> mapOracleJob = markSms(MachineAlarmEnum.MACHINE_ALARM_LOCATION.getAlarmCode());
        /**获取区域*/
        List<Integer> listAccountId = markAccountId(mapOracleJob, SMS_ZC);

        if (listAccountId != null && listAccountId.size() > 0) {
            for (Integer key : mapOracleJob.keySet()) {
                //获取车辆信息
                String location = DateTimeUtil.getHoursAgo(mapOracleJob.get(key).getLocationAlarmTime());
                List<Machine> machineStatuses = machineStatusService.getByAccountIdPosDt(location, key);

                if (machineStatuses.size() > 0) {
                    List<String> userCode = new ArrayList<>();
                    Map<Integer, String> userCodeId = new HashMap<>();
                    for (Machine machine : machineStatuses) {
                        String redisUserCode = redisService.get(RedisConstant.REDIS_KEY_MACHINE + MachineAlarmEnum.MACHINE_ALARM_LOCATION.getAlarmType() + machine.getAccountId() + machine.getUserCode());
                        if (redisUserCode == null) {
                            /* 存放redis一天*/
                            redisService.add(RedisConstant.REDIS_KEY_MACHINE + MachineAlarmEnum.MACHINE_ALARM_LOCATION.getAlarmType() + machine.getAccountId() + machine.getUserCode(), machine.getUserCode(), 24 * 3600);
                            userCode.add(machine.getUserCode());
                            userCodeId.put(machine.getMachineId(), machine.getUserCode());
                        }
                    }
                    if (userCode.size() > 0) {
                        //获取分区id
                        List<Map<String, Object>> mapList = getRegionId(userCodeId);

                        OracleJob oracleJob = mapOracleJob.get(key);
                        //发送短信
                        if (oracleJob.getAccountSms() != null) {
                            sendSmsCL(MachineAlarmEnum.MACHINE_ALARM_LOCATION.getAlarmDesc(), userCode, oracleJob);
                        } else {
                            sendSms(MachineAlarmEnum.MACHINE_ALARM_LOCATION.getAlarmDesc(), userCode, oracleJob);
                        }
                        //插入日志
                        machineAlarmLogService.insertBatchMap(key, MachineAlarmEnum.MACHINE_ALARM_LOCATION.getAlarmType(), mapList, DateTimeUtil.getNowTime());
                    }
                }
            }
        }
        long t2 = System.currentTimeMillis();
        LogUtil.info("无定位预警定时任务时间" + (t2 - t1) + "ms");
    }

    @Override
    //@Scheduled(cron = "0 1/2 * * * ?")
    /**资产预警不还车定时任务*/
    public void returnMachine() {
        LogUtil.info("资产预警不还车定时任务");
        long t1 = System.currentTimeMillis();

        /**获取所有在骑车辆*/
        List<MachineBorrow> machineBorrows = machineBorrowService.getAll();
        List<String> orderNOs = machineBorrows.stream().map(MachineBorrow::getOrderNO).collect(Collectors.toList());
        /**查询骑行订单信息*/
        if (orderNOs != null && orderNOs.size() > 0) {
            List<RideLog> rideLogList = rideLogService.getByOrderNOs(orderNOs);
            Map<String, RideLog> rideLogMap = new HashMap<>();
            for (RideLog rideLog : rideLogList) {
                rideLogMap.put(rideLog.getMachineNO(), rideLog);
            }

            /** 获取配置不换车预警运营区域 */
            for (AccountConfig ac : dataService.getAllAccountConfig()) {
                if (ac.getTimeOutNotice() != 0 && ac.getFinishOrderSwitch()) {
                    /** 查询当前骑行车辆 */
                    List<Machine> machines = machineService.getUseingByAccountId(ac.getAccountId());
                    List<String> machineNOs = machines.stream().map(Machine::getMachineNO).collect(Collectors.toList());

                    if (machineNOs.size() > 0) {
                        /**查询车辆事件*/
                        Map<String, MachineEvent> machineStopMap = new HashMap<String, MachineEvent>();
                        List<MachineEvent> machineStops = machineAttrService.getStopByMachineNOBatch(machineNOs);
                        for (MachineEvent ms : machineStops) {
                            machineStopMap.put(ms.getMachineNO(), ms);
                        }

                        for (Machine machine : machines) {
                            try {
                                /**未激活车辆忽略，单车也忽略*/
                                MachineStatus ms = dataService.getMachineStatus(machine.getMachineId());
                                if (ms == null) {
                                    continue;
                                }
                                RideLog rideLog = rideLogMap.get(machine.getMachineNO());
                                Integer rideTime = DateTimeUtil.getMinutes(rideLog.getStartTime(), DateTimeUtil.getNowTime());

                                Boolean finishOrder = false;
                                Integer stopTime = null;
                                /**获取静止时间*/
                                MachineEvent machineStop = machineStopMap.get(machine.getMachineNO());
                                String orderNo = redisService.get(RedisConstant.REDIS_KEY_MACHINE + rideLog.getOrderNO());
                                if (orderNo != null) {
                                } else {
                                    if (machineStop != null) {
                                        stopTime = DateTimeUtil.getMinutes(machineStop.getEventTime(), DateTimeUtil.getNowTime());

                                        if (ac.getTimeOutNotice() > 0 && stopTime > ac.getTimeOutNotice()) {
                                            /**骑行时间小于设定的未还车时间*/
                                            if (rideTime <= ac.getTimeOutNotice()) {
                                                continue;
                                            }
                                            if (machine.getMachineType() == 1) {
                                                finishOrder = true;
                                            } else {
                                                /**双重校验，设定时间里程也需要小于100米*/
                                                String startTime = DateTimeUtil.getMinsAgo(ac.getTimeOutNotice());
                                                Integer mileage = historyService.getMileageByMachineNOAndTime(machine.getMachineNO(), startTime, DateTimeUtil.getNowTime());
                                                if (mileage == null) {
                                                    mileage = 0;
                                                }
                                                if (mileage < 100) {
                                                    finishOrder = true;
                                                }
                                            }
                                        }
                                        /** 是否临时停车*/
                                        if (ac.getTimeOutNotice() > 0 && stopTime > ac.getTimeOutNotice() && !finishOrder) {
                                            /**骑行时间小于设定的未还车时间*/
                                            if (rideTime <= ac.getTimeOutNotice()) {
                                                continue;
                                            }

                                            /**判断是否车辆运动中*/
                                            MachineEvent machineEvent = machineAttrService.getByMachineNO(machine.getMachineNO(), "1");
                                            if (machineEvent != null) {
                                                Integer runTime = DateTimeUtil.getMinutes(machineEvent.getEventTime(), DateTimeUtil.getNowTime());
                                                if (runTime <= ac.getTimeOutNotice()) {
                                                    continue;
                                                }
                                            }

                                            Park parkDB = parkService.getByMachineId(machine.getMachineId());
                                            if (parkDB == null) {
                                                if (machine.getMachineType() == 1) {
                                                } else {
                                                    /**双重校验，设定时间里程也需要小于100米*/
                                                    String startTime = DateTimeUtil.getMinsAgo(ac.getTimeOutNotice());
                                                    Integer mileage = historyService.getMileageByMachineNOAndTime(machine.getMachineNO(), startTime, DateTimeUtil.getNowTime());
                                                    if (mileage == null) {
                                                        mileage = 0;
                                                    }
                                                    if (mileage > 100) {
                                                        continue;
                                                    }
                                                }
                                                finishOrder = true;
                                            }
                                        }
                                    } else {
                                        /**判断是否车辆运动中*/
                                        MachineEvent machineEvent = machineAttrService.getByMachineNO(machine.getMachineNO(), "1");
                                        if (machineEvent != null) {
                                            Integer runTime = DateTimeUtil.getMinutes(machineEvent.getEventTime(), DateTimeUtil.getNowTime());
                                            if (runTime <= ac.getTimeOutNotice()) {
                                                continue;
                                            }
                                        }

                                        /**防止终端静止时间不准确导致不能结束订单*/
                                        if (ac.getTimeOutNotice() > 0 && rideTime > ac.getTimeOutNotice()) {
                                            if (machine.getMachineType() == 1) {
                                                finishOrder = true;
                                            } else {
                                                String startTime = DateTimeUtil.getMinsAgo(ac.getTimeOutNotice());
                                                Integer mileage = historyService.getMileageByMachineNOAndTime(machine.getMachineNO(), startTime, DateTimeUtil.getNowTime());
                                                if (mileage == null) {
                                                    mileage = 0;
                                                }
                                                if (mileage < 100) {
                                                    finishOrder = true;
                                                }
                                            }
                                        }
                                    }

                                    /**发送未还车短信*/
                                    if (finishOrder) {
                                        /** 获取用户信息*/
                                        User user = userService.getByUserId(rideLog.getUserId());

                                        /**判断是否兼容创蓝*/
                                        BrandRemoteConfig brandRemoteConfig = brandRemoteConfigService.getByAccountIdAndType(user.getAccountId(), BrandRemoteConfigConstant.CL_SMS);
                                        if (brandRemoteConfig != null) {
                                            String[] paramKV = brandRemoteConfig.getParamKV().split("&");
                                            String accountSms = paramKV[0].substring(paramKV[0].lastIndexOf("=") + 1);
                                            String passwordSms = paramKV[1].substring(paramKV[1].lastIndexOf("=") + 1);
                                            /* 发送短信*/
                                            ThreadPoolHelper.submit(new Runnable() {
                                                @Override
                                                public void run() {
                                                    try {
                                                        if (user.getPhone() != null) {
                                                            ClzySmsAuthUtil.sendSms(accountSms, passwordSms, "您的骑行订单静止超过" + ac.getTimeOutNotice() + "分钟未还车，请及时还车，避免产生额外的费用。", user.getPhone());
                                                            redisService.add(RedisConstant.REDIS_KEY_MACHINE + rideLog.getOrderNO(), DateTimeUtil.getNowTime(), 60 * 60 * 24);
                                                        }
                                                    } catch (Exception e) {
                                                        LogUtil.info(rideLog.getOrderNO() + "发送未还车预警短信失败");
                                                        log.error(e.getMessage(), e);
                                                    }
                                                }
                                            });
                                        } else {
                                            /** 获取短信模板*/
                                            AccountSmsModel accountSmsModel = dataService.getAccountSmsModel(user.getAccountId() + ":" + AccountSmsModelConstant.SMS_WHC);
                                            if (accountSmsModel == null) {
                                                LogUtil.info(user.getAccountId() + "没有配置未还车短信模板");
                                            }
                                            SmsAuthConfig smsAuthConfig = smsAuthConfigService.getByAccountId(user.getAccountId());

                                            /** 发送短信*/
                                            ThreadPoolHelper.submit(new Runnable() {
                                                @Override
                                                public void run() {
                                                    try {
                                                        XCSmsClient.notReturnCar(user.getPhone(), ac.getTimeOutNotice() + "", smsAuthConfig.getSmsCodeKey(), accountSmsModel.getModelId());
                                                        redisService.add(RedisConstant.REDIS_KEY_MACHINE + rideLog.getOrderNO(), DateTimeUtil.getNowTime(), 60 * 60 * 24);
                                                    } catch (Exception e) {
                                                        LogUtil.info(rideLog.getOrderNO() + "发送未还车预警短信失败");
                                                        log.error(e.getMessage(), e);
                                                    }
                                                }
                                            });
                                        }


                                    }
                                }
                            } catch (Exception e) {
                                log.error(e.getMessage(), e);
                                log.info("错误:{}", e);
                            }
                        }
                    }
                }
            }
        }

        long t2 = System.currentTimeMillis();
        LogUtil.info("未还车预警定时任务时间" + (t2 - t1) + "ms");
    }

    @Override
    //@Scheduled(cron = "0 0 4 * * ?")
    /**用户最后扫码记录定时任务*/
    public void machineLastUserLog() {
        LogUtil.info("用户最后扫码记录定时任务！");
        long t1 = System.currentTimeMillis();

        List<Integer> machineId = machineLastUseLogService.getByMachineNoCount();

        if (machineId != null && machineId.size() > 0) {
            machineLastUseLogService.deleteMachineId(machineId);
        }
        long t2 = System.currentTimeMillis();
        LogUtil.info("用户最后扫码记录定时任务时间" + (t2 - t1) + "ms");
    }

    @Override
    //@Scheduled(cron = "0 3/10 * * * ?")
    /**批量运维车辆轨迹更新*/
    public void mainCarHistory() throws Exception {
        LogUtil.info("批量运维车辆轨迹更新");
        long t1 = System.currentTimeMillis();

        /**获取所有设备编号*/
        List<String> machineNOs = mainCarService.getAllMachineNO();

        if (machineNOs.size() > 0) {
            String GPSToken = redisService.get(RedisConstant.REDIS_GPS);
            if (GPSToken == null) {
                GPSToken = GPSUtil.login();
                redisService.add(RedisConstant.REDIS_GPS, GPSToken, 59 * 60 * 2);
            }
            /**GPS查车*/
            List<CarHistory> carHistories = GPSUtil.findlastpos(GPSToken, StringUtil.getString(machineNOs));

            List<MainCar> mainCars = new LinkedList<>();
            for (CarHistory carHistory : carHistories) {
                MainCar mainCar = new MainCar();
                mainCar.setMachineNO(carHistory.getDevice_no());
                mainCar.setLat(carHistory.getLat());
                mainCar.setLon(carHistory.getLon());
                mainCar.setPosTime(DateTimeUtil.timeToStr(carHistory.getGps_time()));
                mainCar.setUpdateTime(DateTimeUtil.getNowTime());
                mainCars.add(mainCar);
            }
            if (mainCars.size() > 0) {
                mainCarService.updateBatch(mainCars);
            }
        }
        long t2 = System.currentTimeMillis();
        LogUtil.info("批量运维车辆轨迹更新时间：" + (t2 - t1) + "ms");
    }

    @Override
    //@Scheduled(cron = "0 0 1/6 * * ?")
    /**资产预警丢失车辆定时任务*/
    public void userCodeLose() {
        LogUtil.info("资产预警丢失车辆定时任务！");
        long t1 = System.currentTimeMillis();

        /**获取短信*/
        Map<Integer, OracleJob> mapOracleJob = markSms(MachineAlarmEnum.MACHINE_ALARM_LOSE.getAlarmCode());

        /**获取区域*/
        List<Integer> listAccountId = markAccountId(mapOracleJob, SMS_DS);

        /**获取已被再次扫码的车辆*/
        List<MachineLose> machineLoses = machineLoseService.getUseMachine();

        Map<Integer, List<String>> map = new HashMap<>();
        Map<Integer, Map<Integer, String>> userCodeIds = new HashMap<>();

        /**获取区域-车辆信息*/
        for (MachineLose machineLose : machineLoses) {
            if (map.containsKey(machineLose.getAccountId())) {
                map.get(machineLose.getAccountId()).add(machineLose.getUserCode());
                userCodeIds.get(machineLose.getAccountId()).put(machineLose.getMachineId(), machineLose.getUserCode());
            } else {
                List<String> userCode = new LinkedList<>();
                userCode.add(machineLose.getUserCode());
                map.put(machineLose.getAccountId(), userCode);

                Map<Integer, String> userCodeId = new HashMap<>();
                userCodeId.put(machineLose.getMachineId(), machineLose.getUserCode());
                userCodeIds.put(machineLose.getAccountId(), userCodeId);
            }
        }

        /**发送短信*/
        if (listAccountId != null && listAccountId.size() > 0) {
            for (Integer key : mapOracleJob.keySet()) {
                if (map.containsKey(key)) {
                    List<String> userCode = map.get(key);

                    List<Machine> machines = machineService.getByUserCodes(userCode);

                    /**获取车辆最后扫码人位置*/
                    List<Integer> machineIds = machines.stream().map(Machine::getMachineId).collect(Collectors.toList());

                    List<MachineLastUse> machineLastUses = machineLastUseService.getByMachineIds(machineIds);
                    Map<Integer, MachineLastUse> machineStatusMap = new HashMap<>();
                    for (MachineLastUse machineStatus : machineLastUses) {
                        machineStatusMap.put(machineStatus.getMachineId(), machineStatus);
                    }

                    Map<String, MachineLastUse> machineStatusMapM = new HashMap<>();
                    for (Machine machine : machines) {
                        machineStatusMapM.put(machine.getUserCode(), machineStatusMap.get(machine.getMachineId()));
                    }

                    //获取分区id
                    List<Map<String, Object>> mapList = getRegionId(userCodeIds.get(key));

                    OracleJob oracleJob = mapOracleJob.get(key);
                    if (oracleJob.getAccountSms() != null) {
                        sendSmsCLLose(MachineAlarmEnum.MACHINE_ALARM_LOSE.getAlarmDesc(), userCode, oracleJob, machineStatusMapM);
                    } else {
                        //发送短信
                        sendSmsLose(MachineAlarmEnum.MACHINE_ALARM_LOSE.getAlarmDesc(), userCode, oracleJob, machineStatusMapM);
                    }

                    //插入日志
                    machineAlarmLogService.insertBatchMap(key, MachineAlarmEnum.MACHINE_ALARM_LOSE.getAlarmType(), mapList, DateTimeUtil.getNowTime());
                }
            }
        }
        long t2 = System.currentTimeMillis();
        LogUtil.info("资产预警丢失车辆定时任务时间：" + (t2 - t1) + "ms");
    }

    @Override
    //@Scheduled(cron = "0 1/2 * * * ?")
    /**资产预警未关电池锁定时任务*/
    public void batteryLock() {
        LogUtil.info("资产预警未关电池锁定时任务！");
        long t1 = System.currentTimeMillis();

        /**获取所有无信号资产预警配置，添加到数据集合*/
        Map<Integer, OracleJob> mapOracleJob = markSms(MachineAlarmEnum.MACHINE_ALARM_BATTER_LOCK.getAlarmCode());

        /**获取所有短信模板配置*/
        List<Integer> listAccountId = markAccountId(mapOracleJob, SMS_ZC);
        /**发短信集合*/
        Map<Integer, List<String>> smsUserCode = new HashMap<>();
        Map<Integer, String> userCodeId = new HashMap<>();

        /**异常集合*/
        List<Integer> machineIdsAdd = new LinkedList<>();
        List<Integer> machineIdsDel = new LinkedList<>();

        /**加载所有的未关电池锁设备*/
        List<Integer> abnormalMachineIds = machineAbnormalService.getByAbnormalType(MachineAbnormalConstant.MACHINE_ABNORMAL_DCS);

        List<Integer> accountIds = new LinkedList<>();
        for (Integer key : mapOracleJob.keySet()) {
            accountIds.add(key);
        }

        if (accountIds != null && accountIds.size() > 0) {
            /**获取所有的车辆*/
            List<Machine> machines = machineService.getState(accountIds);
            for (Machine machine : machines) {

                String json = redisService.getGetWay(RedisUtil.getTerHashId(machine.getMachineNO()), RedisConstant.REDIS_TER_LAST_STATUS);

                if (json != null && json.length() > 0) {

                    TerLastStatus terLastStatus = JSON.parseObject(json, TerLastStatus.class);
                    Integer terStatus = terLastStatus.getCarStatus();

                    /**开锁*/
                    if (!ObjectUtil.statusParse(7, Integer.valueOf(terStatus))) {

                        /**不存在,添加*/
                        if (!abnormalMachineIds.contains(machine.getMachineId())) {
                            String time = redisService.get(RedisConstant.REDIS_BATTERY_LOCK + machine.getMachineNO());
                            if (time != null) {

                                if ((System.currentTimeMillis() - Long.valueOf(time)) >= 120000) {
                                    machineIdsAdd.add(machine.getMachineId());
                                    redisService.del(RedisConstant.REDIS_BATTERY_LOCK + machine.getMachineNO());

                                    /**添加告警日志*/
                                    if (listAccountId.contains(machine.getAccountId())) {
                                        if (smsUserCode.containsKey(machine.getAccountId())) {
                                            smsUserCode.get(machine.getAccountId()).add(machine.getUserCode());
                                        } else {
                                            List<String> userCode = new LinkedList<>();
                                            userCode.add(machine.getUserCode());
                                            smsUserCode.put(machine.getAccountId(), userCode);
                                        }
                                        userCodeId.put(machine.getMachineId(), machine.getUserCode());
                                    }
                                }
                            } else {
                                redisService.add(RedisConstant.REDIS_BATTERY_LOCK + machine.getMachineNO(), System.currentTimeMillis() + "", 600);
                            }
                        }
                    } else {
                        /**关锁,存在删除*/
                        if (abnormalMachineIds.contains(machine.getMachineId())) {
                            machineIdsDel.add(machine.getMachineId());
                        }
                    }
                }
            }

            /**资产预警*/
            if (listAccountId != null && listAccountId.size() > 0) {
                for (Integer key : mapOracleJob.keySet()) {
                    if (smsUserCode.get(key) != null && smsUserCode.get(key).size() > 0) {
                        List<Map<String, Object>> mapList = getRegionId(userCodeId);

                        OracleJob oracleJob = mapOracleJob.get(key);
                        //发送短信
                        if (oracleJob.getAccountSms() != null) {
                            sendSmsCL(MachineAlarmEnum.MACHINE_ALARM_BATTER_LOCK.getAlarmDesc(), smsUserCode.get(key), oracleJob);
                        } else {
                            sendSms(MachineAlarmEnum.MACHINE_ALARM_BATTER_LOCK.getAlarmDesc(), smsUserCode.get(key), oracleJob);
                        }

                        //插入日志
                        machineAlarmLogService.insertBatchMap(key, MachineAlarmEnum.MACHINE_ALARM_BATTER_LOCK.getAlarmType(), mapList, DateTimeUtil.getNowTime());
                    }
                }
            }

            /**添加异常*/
            machineAbnormalService.insertBatch(machineIdsAdd, MachineAbnormalConstant.MACHINE_ABNORMAL_DCS, DateTimeUtil.getNowTime());
            /**删除异常*/
            machineAbnormalService.deleteBatch(machineIdsDel, MachineAbnormalConstant.MACHINE_ABNORMAL_DCS);
        }

        long t2 = System.currentTimeMillis();
        LogUtil.info("未关电池锁定时任务时间" + (t2 - t1) + "ms");
    }

    /**
     * 寻程发送预警短信
     *
     * @param type
     * @param userCodes
     * @param oracleJob
     */
    public void sendSms(String type, List<String> userCodes, OracleJob oracleJob) {

        String userCodeString = null;
        if (userCodes != null && userCodes.size() > 10) {
            userCodeString = userCodes.size() + "辆";
        } else {
            userCodeString = StringUtil.getListToString(userCodes);
        }
        /* 发送短信*/
        log.info("发送短信预警，手机号：" + oracleJob.getPhone());
        String finalUserCodeString = userCodeString;
        if (oracleJob.getPhone() != null) {
            String[] strArr = oracleJob.getPhone().split("\\,");
            for (int i = 0; i < strArr.length; ++i) {
                XCSmsClient.sendMachineAlarm(strArr[i], finalUserCodeString, type, oracleJob.getSmsCodeKey(), oracleJob.getModelId(), oracleJob.getAccountName());
            }
            LogUtil.info("运营区域id:" + oracleJob.getAccountName() + " 手机号：" + oracleJob.getPhone() + " 车辆编号：" + userCodes + "发送" + type + "成功");
        }
    }

    /**
     * 寻程发送未还车预警短信
     *
     * @param type
     * @param userCodes
     * @param oracleJob
     */
    public void sendSmsLose(String type, List<String> userCodes, OracleJob oracleJob, Map<String, MachineLastUse> machineStatuses) {

        log.info("发送短信预警，手机号：" + oracleJob.getPhone());

        Map<String, String> map = new HashMap<>();
        for (String userCode : userCodes) {
            map.put(userCode, TXHttpClient.getAddress(machineStatuses.get(userCode).getLo(), machineStatuses.get(userCode).getLa()));
        }

        if (oracleJob.getPhone() != null) {
            String[] strArr = oracleJob.getPhone().split("\\,");
            for (int i = 0; i < strArr.length; ++i) {
                for (String userCode : userCodes) {
                    XCSmsClient.sendLostMachineAlarm(strArr[i], userCode, type, oracleJob.getSmsCodeKey(), oracleJob.getModelId(), oracleJob.getAccountName(), map.get(userCode));
                }
            }
        }
    }

    /**
     * 创蓝发送预警短信
     *
     * @param type
     * @param userCodes
     * @param oracleJob
     */
    public void sendSmsCL(String type, List<String> userCodes, OracleJob oracleJob) {

        String userCodeString = null;
        if (userCodes != null && userCodes.size() > 10) {
            userCodeString = userCodes.size() + "辆";
        } else {
            userCodeString = StringUtil.getListToString(userCodes);
        }
        /* 发送短信*/
        log.info("发送短信预警，手机号：" + oracleJob.getPhone());
        String finalUserCodeString = userCodeString;
        if (oracleJob.getPhone() != null) {
            String[] strArr = oracleJob.getPhone().split("\\,");
            for (int i = 0; i < strArr.length; ++i) {
                ClzySmsAuthUtil.sendSms(oracleJob.getAccountSms(), oracleJob.getPasswordSms(), "资产安全预警提醒：车辆预警：" + oracleJob.getAccountName() + "车辆" + finalUserCodeString + "产生" + type + "异常，请及时处理", strArr[i]);
            }
        }
    }

    /**
     * 创蓝发送未还车预警短信
     *
     * @param type
     * @param userCodes
     * @param oracleJob
     */
    public void sendSmsCLLose(String type, List<String> userCodes, OracleJob oracleJob, Map<String, MachineLastUse> machineStatuses) {

        /* 发送短信*/
        log.info("发送短信预警，手机号：" + oracleJob.getPhone());

        Map<String, String> map = new HashMap<>();
        for (String userCode : userCodes) {
            map.put(userCode, TXHttpClient.getAddress(machineStatuses.get(userCode).getLo(), machineStatuses.get(userCode).getLa()));
        }

        if (oracleJob.getPhone() != null) {
            String[] strArr = oracleJob.getPhone().split("\\,");
            for (int i = 0; i < strArr.length; ++i) {
                for (String userCode : userCodes) {
                    ClzySmsAuthUtil.sendSms(oracleJob.getAccountSms(), oracleJob.getPasswordSms(), "资产安全预警提醒：车辆预警：" + oracleJob.getAccountName() + "车辆" + userCode + "产生" + type + "异常，最后扫码地址为" + map.get(userCode) + "请及时处理", strArr[i]);
                }
            }
        }
    }

    /**
     * 获取资产预警开关
     *
     * @param alarmSwitch
     * @return
     */
    public Map<Integer, OracleJob> markSms(String alarmSwitch) {
        List<MachineAlarm> listMachineAlarm = machineAlarmService.getType(alarmSwitch);

        Map<Integer, OracleJob> mapOracleJob = new HashMap<>();
        for (MachineAlarm machineAlarm : listMachineAlarm) {
            OracleJob oracleJob = new OracleJob();

            if (alarmSwitch.equals(MachineAlarmEnum.MACHINE_ALARM_LOCATION.getAlarmCode())) {
                oracleJob.setLocationAlarmTime(machineAlarm.getLocationAlarmTime());

            } else if (alarmSwitch.equals(MachineAlarmEnum.MACHINE_ALARM_IDLE.getAlarmCode())) {
                oracleJob.setIdleAlarmTime(machineAlarm.getIdleAlarmTime());

            } else if (alarmSwitch.equals(MachineAlarmEnum.MACHINE_ALARM_GEO.getAlarmCode())) {
                oracleJob.setPoints(dataService.getGeo(machineAlarm.getAccountId()));

            } else if (alarmSwitch.equals(MachineAlarmEnum.MACHINE_ALARM_OFFLINE.getAlarmCode())) {
                oracleJob.setOfflineAlarmTime(machineAlarm.getOfflineAlarmTime());
            }
            oracleJob.setPhone(machineAlarm.getAlarmPhone());
            oracleJob.setAccountName(machineAlarm.getName());
            mapOracleJob.put(machineAlarm.getAccountId(), oracleJob);
        }
        return mapOracleJob;
    }

    /**
     * 获取运营区域配置
     *
     * @param mapOracleJob
     * @param smsModel
     * @return
     */
    public List<Integer> markAccountId(Map<Integer, OracleJob> mapOracleJob, Integer smsModel) {
        /**获取所有短信模板配置*/
        List<Integer> listAccountId = new ArrayList<>();
        Iterator<Map.Entry<Integer, OracleJob>> it = mapOracleJob.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<Integer, OracleJob> entry = it.next();
            OracleJob oracleJob = mapOracleJob.get(entry.getKey());

            /**判断是否兼容创蓝*/
            BrandRemoteConfig brandRemoteConfig = brandRemoteConfigService.getByAccountIdAndType(dataService.getParentId(entry.getKey()), BrandRemoteConfigConstant.CL_SMS);
            AccountSmsModel accountSmsModel = dataService.getAccountSmsModel(dataService.getParentId(entry.getKey()) + ":" + smsModel);
            if (brandRemoteConfig != null) {
                String[] paramKV = brandRemoteConfig.getParamKV().split("&");
                oracleJob.setAccountSms(paramKV[0].substring(paramKV[0].lastIndexOf("=") + 1));
                oracleJob.setPasswordSms(paramKV[1].substring(paramKV[1].lastIndexOf("=") + 1));
                mapOracleJob.put(entry.getKey(), oracleJob);
                listAccountId.add(entry.getKey());
            } else if (accountSmsModel != null) {
                oracleJob.setSmsCodeKey(accountSmsModel.getSmsCodeKey());
                oracleJob.setModelId(accountSmsModel.getModelId());
                mapOracleJob.put(entry.getKey(), oracleJob);
                listAccountId.add(entry.getKey());
            } else {
                it.remove();
            }
        }
        return listAccountId;
    }

    /**
     * 获取分区id
     *
     * @param userCodeId
     * @return
     */
    public List<Map<String, Object>> getRegionId(Map<Integer, String> userCodeId) {
        List<Map<String, Object>> mapList = new LinkedList<>();
        List<Integer> machineIds = new LinkedList<>();
        for (Integer KeyId : userCodeId.keySet()) {
            machineIds.add(KeyId);
        }
        //获取分区id
        List<GeoreMachine> geoMachines = georeMachineService.getByMachineIds(machineIds);
        Map<Integer, Integer> mapGeo = new HashMap<>();
        for (GeoreMachine georeMachine : geoMachines) {
            mapGeo.put(georeMachine.getMachineId(), georeMachine.getRegionId());
        }

        //拼接数据
        for (Integer KeyId : userCodeId.keySet()) {
            Map<String, Object> map = new HashMap<>();
            map.put("userCode", userCodeId.get(KeyId));
            if (mapGeo.containsKey(KeyId)) {
                map.put("regionId", mapGeo.get(KeyId));
            } else {
                map.put("regionId", null);
            }
            mapList.add(map);
        }
        return mapList;
    }
}
